﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using HydroDesktop.Database.Tests.MappingTests.DataRepository;
using log4net;
//using NinjaCross.Classes.FireBenchmarks.NUnitAddIn.Core;
using NinjaCross.Classes.FireBenchmarks.NUnitAddIn.Core;
using NUnit.Framework;
using HydroDesktop.ObjectModel;

namespace HydroDesktop.Database.Tests.PerformanceTests
{
    [TestFixture]
    public class SeriesManagerPerformanceTest
    {
        static Random random = new Random();
        static ILog perfLog = LogManager.GetLogger("PerfTest");
        private RepositoryManager manager;

        [SetUp]
        public void SetupManager()
        {
            manager = GetManager();
        }

        [Test]
        [NJC_TestPerformanceRecorder
        (
        OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
        OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
        OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
        OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
        )]
        public void SaveSeriesNoSeries()
        {
            SaveSeriesNoData(10);
        }

        [TestCase(10)]
        [TestCase(100)]
        // [TestCase(1000)]
        //[TestCase(10000)]
        public void SaveSeriesNoData(int runSize)
        {
            int rnd = random.Next(1000);
            DateTime startTime = DateTime.Now;
            DateTime latstTime = startTime;

            perfLog.Info("Starting LoadAndCheckExistingSeries loops:" + runSize);



            perfLog.Info("Initialize Repository Manager" + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;
            //a theme is created
            Theme theme1 = ThemesTest.CreateTheme();


            perfLog.Info("Initialized theme" + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;

            //a series is created and saved to database

            List<Series> series = new List<Series>(runSize);
            for (int i = 0; i < runSize; i++)
            {
                series.Add(DataSeriesTest.CreateSeries(random.Next()));

            }
            perfLog.Info("Created Series" + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;

            //  manager.BeginTransaction();
            foreach (Series s in series)
            {
                manager.SaveSeries(s, theme1, OverwriteOptions.Copy);

            }
            perfLog.Info("Saved Series" + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;


            //  manager.Commit();

            ////a new identical series is created in-memory
            //Series series2 = HydroDesktop.Database.Tests.DataSeriesTest.CreateSeries(rnd);
            //series2.Site = series1.Site;
            //series2.Variable = series1.Variable;
            //series2.Method = series1.Method;
            //series2.QualityControlLevel = series1.QualityControlLevel;
            //series2.Source = series1.Source;

            //Series existing = manager.SeriesDAO.CheckForExisting(series2);

            //Assert.AreEqual(series2.Id, 0, "series2 should be unsaved (id==0)");
            //Assert.AreNotEqual(existing.Id, 0, "the 'existing' series should be retrieved from db (id > 0)");

            //the 'existing' series should be equal to 'series1' previously saved
            //Assert.AreEqual(existing, series1, "The 'existing' series should be equal to 'series1' previously saved.");
            foreach (Series s in series)
            {
                Series fromDB = manager.SeriesDAO.CheckForExisting(s);

                Assert.AreEqual(s.ValueCount, fromDB.ValueCount, "the retrieved series should have no values.");
                Assert.AreEqual(s.ValueCount, fromDB.ValueCount, "the retrieved series should have no values.");
            }
        }

        [Test]
        [NJC_TestPerformanceRecorder
    (
    OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
    OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
    OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
    OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
    )]
        public void CanSaveSeriesWithDataValuesNoQualifiers()
        {
            CanSaveSeriesWithDataValues2(1000, false);
        }

        [Test]
        [NJC_TestPerformanceRecorder
    (
    OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
    OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
    OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
    OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
    )]
        public void CanSaveSeriesWithDataValuesWithQualiers()
        {
            CanSaveSeriesWithDataValues2(1000, false);
        }

        [Test, Combinatorial]
        [Category("BigTests")]
        public void CanSaveSeriesWithDataValues2(
            [Values(100, 1000, 10000, 50000, 100000, 500000)]int runSize,
            [Values(true, false)]bool withQualifiers)
        {
            int rnd = random.Next(1000);

            DateTime startTime = DateTime.Now;
            DateTime latstTime = startTime;

            perfLog.Info("Starting CanSaveSeriesWithDataValues2 datavalues:" + runSize + " Qualifiers=" + withQualifiers);


            perfLog.Info("Initialize Repository Manager" + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;

            //a series with default site, variable, method and quality control is created..
            Series series1 = DataSeriesTest.CreateSeries(rnd);
            perfLog.Info("created series" + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;
            for (int i = 0; i < runSize; i++)
            {
                series1.AddDataValue(DateTime.Now.Date.AddMinutes(runSize - i), rnd);

                if (withQualifiers)
                {
                    series1.DataValueList[0].Qualifier = QualifiersTest.CreateQualifier();
                }
            }
            perfLog.Info("created " + runSize + "DataValues. " + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;

            string siteName = series1.Site.Name;
            Theme myTheme = new Theme("My Theme", "the testing theme number 1.");

            perfLog.Info("created " + runSize + "DataValues. " + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;

            Assert.AreEqual(runSize, series1.ValueCount, "the created series should have " + runSize + " values.");

            manager.SaveSeries(series1, myTheme, OverwriteOptions.Copy);

            perfLog.Info("Saved series with " + runSize + "DataValues. " + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;

            perfLog.Info("Saved series with " + runSize + "DataValues. " + (DateTime.Now - latstTime).Milliseconds);

            Series fromDB = manager.SeriesDAO.CheckForExisting(series1);

            Assert.AreEqual(runSize, fromDB.ValueCount, "the retrieved series should have " + runSize + " values.");

            Assert.AreEqual(series1.ValueCount, fromDB.ValueCount, "the retrieved series should have values.");
        }

        [Test]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSaveTwoSeries()
        {
            CanSaveManySeries(2, 10, 1);
        }

        [Test]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSaveTwoSeriesToThemes()
        {
            CanSaveManySeries(2, 10, 2);
        }

        [Test]
        [Category("SmallTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave10Series1Value0Theme()
        {
            CanSaveManySeries(10, 1, 0);
        }

        [Test]
        [Category("SmallTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave10Series1Value1Theme()
        {
            CanSaveManySeries(10, 1, 1);
        }

        [Test]
        [Category("SmallTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave50Series1Value0Theme()
        {
            CanSaveManySeries(50, 1, 0);
        }
        [Test]
        [Category("SmallTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave50Series1Value1Theme()
        {
            CanSaveManySeries(50, 1, 1);
        }

        [Test]
        [Category("SmallTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave100Series1Value0Theme()
        {
            CanSaveManySeries(100, 1, 0);
        }
        [Test]
        [Category("SmallTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave100Series1Value1Theme()
        {
            CanSaveManySeries(100, 1, 1);
        }

        [Test]
        [Category("MediumTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave1000Series1Value0Theme()
        {
            CanSaveManySeries(1000, 1, 0);
        }

        [Test]
        [Category("MediumTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave1000Series1Value1Theme()
        {
            CanSaveManySeries(1000, 1, 1);
        }


        [Test]
        [Category("BigTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave10000Series1Value0Theme()
        {
            CanSaveManySeries(10000, 10, 0);
        }
        [Test]
        [Category("BigTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave10000Series1Value1Theme()
        {
            CanSaveManySeries(10000, 1, 1);
        }
        [Test]
        [Category("BigTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave100kSeries1Value0Theme()
        {
            CanSaveManySeries(100000, 1, 0);
        }
        [Test]
        [Category("BigTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave100kSeries1Value1Theme()
        {
            CanSaveManySeries(100000, 1, 1);
        }

        [Test]
        [Category("BigTests")]
        [NJC_TestPerformanceRecorder
(
OutputTargetFormat = NJC_TestPerformanceTargetFormat.Html, // Xhtml file output
OutputTargetIdentificationFormat = NJC_TestPerformanceTargetIdentificationFormat.MethodName, // full method name
OutputTarget = "..\\PerformanceRepository\\DataRepository", // in real-world code, a constant would be better
OutputTargetWriteMode = NJC_TestPerformanceTargetWriteMode.Append // append to previous trackings
)]
        public void CanSave1MilSeries1Value0Theme()
        {
            CanSaveManySeries(1000000, 1, 0);
        }

        [TestCase(1, 10, 1)]
        [TestCase(2, 10, 2)]
        [TestCase(2, 10, 2)]
        public void CanSaveManySeries(int numberOfSeries, int dataValueCount, int numberOfThemes)
        {

            DateTime startTime = DateTime.Now;
            DateTime latstTime = startTime;

            perfLog.Info("Starting CanSaveManySeries numberOfSeries:" + numberOfSeries + " numberOfThemes=" + numberOfThemes);


            perfLog.Info("Initialize Repository Manager" + (DateTime.Now - latstTime).Milliseconds);
            latstTime = DateTime.Now;
            int rnd = random.Next(1000);
            List<Theme> themes = new List<Theme>(numberOfThemes);
            List<Series> series = new List<Series>(numberOfSeries);
            
            perfLog.Info("creating " + numberOfThemes + " themes" + (DateTime.Now - latstTime).Milliseconds);

            for (int i = 0; i < numberOfThemes; i++)
            {
                themes.Add(new Theme("my theme " + i, "theme " + i));
            }
            perfLog.Info("created " + numberOfThemes + " themes in:" + (DateTime.Now - latstTime).Milliseconds);

            Site mySite = SitesTest.CreateSite(rnd);
            mySite.Name = "MY SITE 1";

            DateTime baseDate = new DateTime(2009, 1, 1);
            perfLog.Info("creating " + numberOfSeries + " series in:" + (DateTime.Now - latstTime).Milliseconds);

            for (int n = 0; n < numberOfSeries; n++)
            {

                Series series2 = DataSeriesTest.CreateSeries(rnd);
                series2.Site = mySite;

                //add some values to both series
                for (int i = 0; i < dataValueCount; i++)
                {
                    int val = random.Next(1000);
                    DataValuesTest.CreateDataValue(val * 2, series2, baseDate.AddDays(i));
                }
                series.Add(series2);
            }
            perfLog.Info("created " + numberOfSeries + " series in:" + (DateTime.Now - latstTime).Milliseconds);

            perfLog.Info("Saving " + numberOfSeries + " series in " + numberOfThemes + " themes :" + (DateTime.Now - latstTime).Milliseconds);
            if (numberOfThemes == numberOfSeries)
            {
                for (int n = 0; n < numberOfSeries; n++)
                {
                    //    numSaved += manager.SaveSeries(series[n], themes[n], OverwriteOptions.Copy);

                    manager.SaveSeries(series[n], themes[n], OverwriteOptions.Copy);
                }
            }
            else
            {
                if (numberOfThemes > 0)
                {
                    for (int n = 0; n < numberOfSeries; n++)
                    {
                        int themeN = random.Next(0, numberOfThemes);
                        //            numSaved += manager.SaveSeries(series[n], themes[themeN], OverwriteOptions.Copy);
                        manager.SaveSeries(series[n], themes[themeN], OverwriteOptions.Copy);
                    }
                }
                else
                {
                    for (int n = 0; n < numberOfSeries; n++)
                    {
                        manager.SaveSeries(series[n], null, OverwriteOptions.Copy);
                    }
                }

            }
            perfLog.Info("Saved " + numberOfSeries + " series in " + numberOfThemes + " themes :" + (DateTime.Now - latstTime).Milliseconds);

            perfLog.Info("Completed Run :" + (DateTime.Now - startTime).Milliseconds);
            
            // this is data validation. Not performance related
            //for (int n = 0; n < numberOfSeries; n++)
            //{
            //    Series fromDB = manager.SeriesDAO.CheckForExisting(series[n]);

            //    Assert.AreEqual(series[n].ValueCount, fromDB.ValueCount, "the retrieved series should have " + series[n].ValueCount + " values had fromDB.ValueCount  ");
            //    if (series[n].ThemeList.Count() > 0)
            //    {
            //        Assert.AreEqual(series[n].ThemeList.Count(), fromDB.ThemeList.Count(), "Theme counts do not match");

            //    }
            //}
        }

        static RepositoryManager GetManager()
        {
            return Config.RepositoryManager;
        }

    }
}